package com.zym.init.controller;

import com.alibaba.fastjson2.JSONObject;
import com.zym.init.core.annotation.Anonymous;
import com.zym.init.core.cache.StorageCache;
import com.zym.init.core.controller.BaseController;
import com.zym.init.core.exception.ServiceException;
import com.zym.init.core.utils.AesUtils;
import com.zym.init.enums.StorageServiceProviderEnum;
import com.zym.init.model.po.ResourcePo;
import com.zym.init.model.po.StoragePo;
import com.zym.init.service.ResourceService;
import com.zym.init.service.StorageService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

@Slf4j
@RestController
public class CommonController extends BaseController {

    private final ResourceService resourceService;
    private final StorageService storageService;

    public CommonController(ResourceService resourceService, StorageService storageService) {
        this.resourceService = resourceService;
        this.storageService = storageService;
    }

    /**
     * 在线预览资源文件
     *
     * @param key 加密后的对象 {'id': 22}
     * @return 资源文件
     */
    @Anonymous
    @GetMapping("/v/{key}")
    public ResponseEntity<byte[]> getResource(HttpServletResponse response, @PathVariable String key) {
        // 解密 key 获取资源 ID
        String encrypt = AesUtils.decrypt(key);
        JSONObject jsonObject = JSONObject.parseObject(encrypt);
        Long id = jsonObject.getLong("id");

        // 从缓存中获取资源信息
        ResourcePo rPo = resourceService.getById(id);
        if (rPo == null) {
            throw new ServiceException("资源不存在");
        }

        // 从缓存中获取存储配置信息
        StoragePo sPo = StorageCache.get(rPo.getStorageId());
        if (sPo == null) {
            // 缓存未命中,从数据库查询
            sPo = storageService.getById(rPo.getStorageId());
            if (sPo == null) {
                throw new ServiceException("存储配置不存在");
            }
            // 将存储配置信息放入缓存
            StorageCache.set(rPo.getStorageId());
        }

        // 拼接文件完整路径
        if (sPo.getServiceProvider().equals(StorageServiceProviderEnum.LOCAL.getServiceProvider())) {
            return getLocalResource(sPo, rPo);
        } else if (sPo.getServiceProvider().equals(StorageServiceProviderEnum.MINIO.getServiceProvider())) {
            String endpoint = sPo.getStorageConfig().get("endpoint");
            String bucketName = sPo.getStorageConfig().get("bucket_name");
            if (!StringUtils.hasLength(endpoint)) {
                throw new ServiceException("未设置endpoint，无法读取文件");
            }
            if (!StringUtils.hasLength(bucketName)) {
                throw new ServiceException("未设置bucketName，无法读取文件");
            }
            String url = endpoint + "/" + bucketName + "/" + rPo.getPath();
            try {
                response.sendRedirect(url);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return null;
        }

        throw new ServiceException("未找到对应的存储方式，无法读取文件");
    }

    /**
     * 获取本地文件
     *
     * @param sPo 存储配置
     * @param rPo 文件信息
     * @return ResponseEntity
     */
    private static ResponseEntity<byte[]> getLocalResource(StoragePo sPo, ResourcePo rPo) {
        // 拼接文件完整路径
        String storagePath = sPo.getStorageConfig().get("storage_path");
        String filePath = storagePath + "/" + rPo.getPath();

        // 根据文件扩展名确定 MIME 类型
        MediaType mediaType = MediaType.parseMediaType(rPo.getMediaType());

        // 判断文件是否存在
        File file = new File(filePath);
        if (!file.exists()) {
            throw new ServiceException("资源已被删除");
        }

        // 读取文件内容
        byte[] fileContent;
        try {
            fileContent = Files.readAllBytes(file.toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 设置响应状态码
        HttpStatus status = HttpStatus.OK;

        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.clear();
        headers.setContentType(mediaType);
        headers.setContentLength(fileContent.length);
        String fileName = rPo.getResourceName() + "." + rPo.getFileExtension();
        headers.setContentDisposition(ContentDisposition.builder("inline").filename(fileName).build());

        // 如果是视频文件，需要设置 Range 头
        if (mediaType.getType().equals("video")) {
            // 设置响应状态码为 206
            status = HttpStatus.PARTIAL_CONTENT;
            // 设置 Range 头
            headers.set("Accept-Ranges", "bytes");
            headers.set("Content-Range", "bytes 0-" + (fileContent.length - 1) + "/" + fileContent.length);
        }

        // 返回 ResponseEntity
        return new ResponseEntity<>(fileContent, headers, status);
    }
}
